package com.hedl.practice.diyJava.encryptionandsecurity.password_encryption_algorithm.test;

import org.bouncycastle.jce.provider.BouncyCastleProvider;

import javax.crypto.*;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.PBEParameterSpec;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.spec.InvalidKeySpecException;
import java.util.Base64;

public class Main {
    //解密：
    private static byte[] decrypt(String password,byte[] salt,byte[] input) throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, InvalidAlgorithmParameterException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
        PBEKeySpec keySpec = new PBEKeySpec(password.toCharArray());
        SecretKeyFactory skeyFactory = SecretKeyFactory.getInstance("PBEwithSHA1and128bitAES-CBC-BC");
        SecretKey skey = skeyFactory.generateSecret(keySpec);
        PBEParameterSpec pbeps = new PBEParameterSpec(salt, 1000);
        Cipher cipher = Cipher.getInstance("PBEwithSHA1and128bitAES-CBC-BC");
        cipher.init(Cipher.DECRYPT_MODE,skey,pbeps);
        return cipher.doFinal(input);
    }

    //加密
    private static byte[] encrypt(String password,byte[] salt,byte[] input) throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, InvalidAlgorithmParameterException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
        PBEKeySpec keySpec = new PBEKeySpec(password.toCharArray());        //toCharArray()将此字符串转换为新的字符数组
        SecretKeyFactory skeyFactory = SecretKeyFactory.getInstance("PBEwithSHA1and128bitAES-CBC-BC");  //该对象转换指定算法的密钥。
        SecretKey skey = skeyFactory.generateSecret(keySpec);   //密钥规范（密钥材料）生成 SecretKey对象。 秘密密钥
        PBEParameterSpec pbeps = new PBEParameterSpec(salt,1000);       //盐,迭代次数。
        Cipher cipher = Cipher.getInstance("PBEwithSHA1and128bitAES-CBC-BC");       //实现请求转换的密码
        cipher.init(Cipher.ENCRYPT_MODE,skey,pbeps);    //skey=加密密钥;pbeps=盐循环1000次的结果
        return cipher.doFinal(input);       //单部分操作中加密或解密数据
    }

    public static void main(String[] args) throws NoSuchAlgorithmException, InvalidAlgorithmParameterException, NoSuchPaddingException, IllegalBlockSizeException, InvalidKeySpecException, BadPaddingException, InvalidKeyException {
        // 把BouncyCastle作为Provider添加到java.security:
        Security.addProvider(new BouncyCastleProvider());
        //原文
        String message = "Hello,World";
        //加密口令
        String password = "hello12345";
        // 16 bytes随机Salt:
        byte[] salt = SecureRandom.getInstanceStrong().generateSeed(16);
        System.out.printf("salt:%032x\n",new BigInteger(1,salt));

        //加密
        byte[] data = message.getBytes(StandardCharsets.UTF_8);     //原文加密
        byte[] encrypted = encrypt(password, salt, data);
        System.out.println("Encrypted："+ Base64.getEncoder().encodeToString(encrypted));

        //解密
        byte[] decrypted = decrypt(password, salt, encrypted);
        System.out.println("Decrypted："+new String(decrypted,StandardCharsets.UTF_8));
    }
    /**
     * 小结：
     *      PBE算法通过用户口令和安全的随机salt计算出Key，然后再进行加密；
     *      Key通过口令和安全的随机salt计算得出，大大提高了安全性；
     *      PBE算法内部使用的仍然是标准对称加密算法（例如AES）。
     */
}
